package fr.vvins.core.biz.community;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.googlecode.ehcache.annotations.Cacheable;

import fr.vvins.core.biz.user.dto.UserCommentDto;
import fr.vvins.core.biz.user.dto.UserLogDto;
import fr.vvins.core.biz.user.dto.UserRatingDtoInfo;
import fr.vvins.core.common.TechnicalException;
import fr.vvins.core.common.dto.DtoException;
import fr.vvins.core.common.dto.DtoFactory;
import fr.vvins.core.common.dto.EntityDtoConverter;
import fr.vvins.core.user.dao.UserCommentRepository;
import fr.vvins.core.user.dao.UserLogRepository;
import fr.vvins.core.user.dao.UserRatingRepository;
import fr.vvins.core.user.entity.UserComment;
import fr.vvins.core.user.entity.UserLog;
import fr.vvins.core.user.entity.UserRating;

// TODO : revoir les double requetes pour les requetes de type content.id et content.key
// car la c'est pas terrible.
public class CommunityManagerImpl implements CommunityManager {

	private final static Logger log = LoggerFactory.getLogger(CommunityManagerImpl.class);
	
	@Autowired
	private DtoFactory dtoFactory;
	
	@Autowired
	private EntityDtoConverter converter;
	
	@Autowired
	private UserLogRepository userLogDao;

	@Autowired
	private UserRatingRepository userRatingDao;
	
	@Autowired
	private UserCommentRepository userCommentDao;
	
	@Override
	@Cacheable(cacheName="log")
	@Transactional
	public Set<UserLogDto> getLogsByProduct(Integer id) throws CommunityException, TechnicalException {
		List<UserLog> logs;
		try {
			logs = userLogDao.findByProductId(id);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		}
		try {
			Set<UserLogDto> logsDto = new HashSet<UserLogDto>();
			if(logs != null && logs.size() > 0){
				for(UserLog log : logs){
					logsDto.add((UserLogDto) getConverter().convertEntityToDto(log));
				}
			}
			return logsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}
	
	@Override
	@Cacheable(cacheName="log")
	@Transactional
	public Set<UserLogDto> getLogsByVigneron(Integer id) throws CommunityException, TechnicalException {
		List<UserLog> logs;
		try {
			logs = userLogDao.findByVigneronId(id);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		}
		try {
			Set<UserLogDto> logsDto = new HashSet<UserLogDto>();
			if(logs != null && logs.size() > 0){
				for(UserLog log : logs){
					logsDto.add((UserLogDto) getConverter().convertEntityToDto(log));
				}
			}
			return logsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}
	
	@Override
	@Cacheable(cacheName="log")
	@Transactional
	public Map<Integer,Set<UserLogDto>> getLogsByProduct(Integer id, List<Integer> actionId) throws CommunityException, TechnicalException {
		List<UserLog> logs = null;
		try {
			logs = userLogDao.findByActionIdAndProductId(actionId,id);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		}
		try {
			Map<Integer,Set<UserLogDto>> logsDto = new HashMap<Integer,Set<UserLogDto>>();
			if(logs != null && logs.size() > 0){
				for(UserLog log : logs){
					Set<UserLogDto> listDto = null;
					Integer acId = log.getAction().getId();
					if(logsDto.containsKey(acId)){
						listDto = logsDto.get(acId);
					} else {
						listDto = new HashSet<UserLogDto>();
					}
					listDto.add((UserLogDto) getConverter().convertEntityToDto(log));
					logsDto.put(acId, listDto);
				}
			}
			return logsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}
	

	@Override
	@Cacheable(cacheName="log")
	@Transactional
	public Map<Integer,Set<UserLogDto>> getLogsByVigneron(Integer id, List<Integer> actionId) throws CommunityException, TechnicalException {
		try {
			List<UserLog> logs = null;
			try {
				logs = userLogDao.findByActionIdAndVigneronId(actionId,id);
			} catch (Throwable e) {
				throw new TechnicalException(TechnicalException.DATABASE,e);
			}
			Map<Integer,Set<UserLogDto>> logsDto = new HashMap<Integer,Set<UserLogDto>>();
			if(logs != null && logs.size() > 0){
				for(UserLog log : logs){
					Set<UserLogDto> listDto = null;
					Integer acId = log.getAction().getId();
					if(logsDto.containsKey(acId)){
						listDto = logsDto.get(acId);
					} else {
						listDto = new HashSet<UserLogDto>();
					}
					listDto.add((UserLogDto) getConverter().convertEntityToDto(log));
					logsDto.put(acId, listDto);
				}
			}
			return logsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}
	
	@Override
	@Cacheable(cacheName="log")
	@Transactional
	public Map<Integer,Set<UserLogDto>> getLogsByContent(Integer contentId, List<Integer> actionId) throws CommunityException, TechnicalException {
		try {
			List<UserLog> productlogs = userLogDao.findByActionIdAndProductId(actionId,contentId);
			List<UserLog> vigneronlogs = userLogDao.findByActionIdAndVigneronId(actionId,contentId);
			List<UserLog> logs = new ArrayList<UserLog>();
			if(productlogs != null){
				logs.addAll(productlogs);
			}
			if(vigneronlogs != null){
				logs.addAll(vigneronlogs);
			}
			Map<Integer,Set<UserLogDto>> logsDto = new HashMap<Integer,Set<UserLogDto>>();
			if(logs != null && logs.size() > 0){
				for(UserLog log : logs){
					Set<UserLogDto> listDto = null;
					Integer acId = log.getAction().getId();
					if(logsDto.containsKey(acId)){
						listDto = logsDto.get(acId);
					} else {
						listDto = new HashSet<UserLogDto>();
					}
					listDto.add((UserLogDto) getConverter().convertEntityToDto(log));
					logsDto.put(acId, listDto);
				}
			}
			return logsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}
	
	@Override
	@Cacheable(cacheName="log")
	@Transactional
	public Map<Integer,Set<UserLogDto>> getLogsByKey(String key, List<Integer> actionId) throws CommunityException, TechnicalException {
		List<UserLog> productlogs = null;
		List<UserLog> vigneronlogs = null;
		try {
			productlogs = userLogDao.findByActionIdAndProductKey(actionId,key);
			vigneronlogs = userLogDao.findByActionIdAndVigneronKey(actionId,key);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		}
		try {
			List<UserLog> logs = new ArrayList<UserLog>();
			if(productlogs != null){
				logs.addAll(productlogs);
			}
			if(vigneronlogs != null){
				logs.addAll(vigneronlogs);
			}
			Map<Integer,Set<UserLogDto>> logsDto = new HashMap<Integer,Set<UserLogDto>>();
			if(logs != null && logs.size() > 0){
				for(UserLog log : logs){
					Set<UserLogDto> listDto = null;
					Integer acId = log.getAction().getId();
					if(logsDto.containsKey(acId)){
						listDto = logsDto.get(acId);
					} else {
						listDto = new HashSet<UserLogDto>();
					}
					listDto.add((UserLogDto) getConverter().convertEntityToDto(log));
					logsDto.put(acId, listDto);
				}
			}
			return logsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}
	
	@Override
	@Cacheable(cacheName="log")
	@Transactional
	public Set<UserLogDto> getLogsByUser(Integer userId, List<Integer> actionId) throws CommunityException, TechnicalException {
		List<UserLog> logs = null;
		try {
			logs = userLogDao.findByActionIdAndUserId(actionId,userId);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		}
		try {
			Set<UserLogDto> logsDto = new HashSet<UserLogDto>();
			if(logs != null && logs.size() > 0){
				for(UserLog log : logs){
					logsDto.add((UserLogDto) getConverter().convertEntityToDto(log));
				}
			}
			return logsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}
	
	@Override
	@Cacheable(cacheName="log")
	@Transactional
	public Set<UserLogDto> getLogsByContent(Integer contentId) throws CommunityException, TechnicalException {
		List<UserLog> productlogs = null;
		List<UserLog> vigneronlogs = null;
		try {
			
			productlogs = userLogDao.findByProductContentId(contentId);
			vigneronlogs = userLogDao.findByVigneronContentId(contentId);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		} 
		try {
			List<UserLog> logs = new ArrayList<UserLog>();
			if(productlogs != null){
				logs.addAll(productlogs);
			}
			if(vigneronlogs != null){
				logs.addAll(vigneronlogs);
			}
			Set<UserLogDto> logsDto = new HashSet<UserLogDto>();
			if(logs != null && logs.size() > 0){
				for(UserLog log : logs){
					logsDto.add((UserLogDto) getConverter().convertEntityToDto(log));
				}
			}
			return logsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}
	
	@Override
	@Cacheable(cacheName="log")
	@Transactional
	public Set<UserLogDto> getLogsByKey(String key) throws CommunityException, TechnicalException {
		List<UserLog> productlogs = null;
		List<UserLog> vigneronlogs = null;
		try {
			productlogs = userLogDao.findByProductContentKey(key);
			vigneronlogs = userLogDao.findByVigneronContentKey(key);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		}
		
		try {
			List<UserLog> logs = new ArrayList<UserLog>();
			if(productlogs != null){
				logs.addAll(productlogs);
			}
			if(vigneronlogs != null){
				logs.addAll(vigneronlogs);
			}
			Set<UserLogDto> logsDto = new HashSet<UserLogDto>();
			if(logs != null && logs.size() > 0){
				for(UserLog log : logs){
					logsDto.add((UserLogDto) getConverter().convertEntityToDto(log));
				}
			}
			return logsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}
	
	@Override
	@Cacheable(cacheName="log")
	@Transactional
	public Set<UserLogDto> getLogsByUser(Integer userId) throws CommunityException, TechnicalException {
		List<UserLog> logs = null;
		try {
			logs = userLogDao.findByUserId(userId);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		}
		try {
			Set<UserLogDto> logsDto = new HashSet<UserLogDto>();
			if(logs != null && logs.size() > 0){
				for(UserLog log : logs){
					logsDto.add((UserLogDto) getConverter().convertEntityToDto(log));
				}
			}
			return logsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}
	
	@Override
	@Cacheable(cacheName="comment")
	@Transactional
	public Set<UserCommentDto> getUserCommentByProduct(Integer id) throws CommunityException, TechnicalException {
		List<UserComment> comments = null;
		try {
			comments = userCommentDao.findByProductId(id);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		} 
		try {	
			Set<UserCommentDto> commentsDto = new HashSet<UserCommentDto>();
			if(comments != null && comments.size() > 0){
				for(UserComment comment : comments){
					commentsDto.add((UserCommentDto) getConverter().convertEntityToDto(comment));
				}
			}
			return commentsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}
	
	@Override
	@Cacheable(cacheName="comment")
	@Transactional
	public Set<UserCommentDto> getUserCommentByVigneron(Integer id) throws CommunityException, TechnicalException {
		List<UserComment> comments = null;
		try {
			comments = userCommentDao.findByVigneronId(id);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		} 
		try {
			Set<UserCommentDto> commentsDto = new HashSet<UserCommentDto>();
			if(comments != null && comments.size() > 0){
				for(UserComment comment : comments){
					commentsDto.add((UserCommentDto) getConverter().convertEntityToDto(comment));
				}
			}
			return commentsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}

	@Override
	@Cacheable(cacheName="comment")
	@Transactional
	public Set<UserCommentDto> getUserCommentByContent(Integer contentId) throws CommunityException, TechnicalException {
		List<UserComment> productcomment = null;
		List<UserComment> vigneroncomment = null;
		try {
			productcomment = userCommentDao.findByVigneronContentId(contentId);
			vigneroncomment = userCommentDao.findByProductContentId(contentId);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		}
		try {
			List<UserComment> comments = new ArrayList<UserComment>();
			if(productcomment != null){
				comments.addAll(productcomment);
			}
			if(vigneroncomment != null){
				comments.addAll(vigneroncomment);
			}
			Set<UserCommentDto> commentsDto = new HashSet<UserCommentDto>();
			if(comments != null && comments.size() > 0){
				for(UserComment comment : comments){
					commentsDto.add((UserCommentDto) getConverter().convertEntityToDto(comment));
				}
			}
			return commentsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}

	@Override
	@Cacheable(cacheName="comment")
	@Transactional
	public Set<UserCommentDto> getUserCommentByKey(String key) throws CommunityException, TechnicalException {
		List<UserComment> productcomment = null;
		List<UserComment> vigneroncomment = null;
		try {
			productcomment = userCommentDao.findByProductContentKey(key);
			vigneroncomment = userCommentDao.findByVigneronContentKey(key);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		}
		try {
			List<UserComment> comments = new ArrayList<UserComment>();
			if(productcomment != null){
				comments.addAll(productcomment);
			}
			if(vigneroncomment != null){
				comments.addAll(vigneroncomment);
			}
			Set<UserCommentDto> commentsDto = new HashSet<UserCommentDto>();
			if(comments != null && comments.size() > 0){
				for(UserComment comment : comments){
					commentsDto.add((UserCommentDto) getConverter().convertEntityToDto(comment));
				}
			}
			return commentsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}

	@Override
	@Cacheable(cacheName="comment")
	@Transactional
	public Set<UserCommentDto> getUserCommentByUser(Integer userId) throws CommunityException, TechnicalException {
		List<UserComment> comments = null;
		try {
			comments = userCommentDao.findByUserId(userId);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		}
		try {
			Set<UserCommentDto> commentsDto = new HashSet<UserCommentDto>();
			if(comments != null && comments.size() > 0){
				for(UserComment comment : comments){
					commentsDto.add((UserCommentDto) getConverter().convertEntityToDto(comment));
				}
			}
			return commentsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}

	@Override
	@Cacheable(cacheName="rating")
	@Transactional
	public Set<UserRatingDtoInfo> getUserRatingByProduct(Integer id) throws CommunityException, TechnicalException {
		List<UserRating> ratings = null;
		try {
			ratings = userRatingDao.findByUserId(id);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		} 
		try {
			Set<UserRatingDtoInfo> ratingsDto = new HashSet<UserRatingDtoInfo>();
			if(ratings != null && ratings.size() > 0){
				for(UserRating rating : ratings){
					ratingsDto.add((UserRatingDtoInfo) getConverter().convertEntityToDto(rating));
				}
			}
			return ratingsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}
	
	@Override
	@Cacheable(cacheName="rating")
	@Transactional
	public Set<UserRatingDtoInfo> getUserRatingByVigneron(Integer id) throws CommunityException, TechnicalException {
		List<UserRating> ratings = null;
		try {
			ratings = userRatingDao.findByVigneronId(id);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		}
		try {
			Set<UserRatingDtoInfo> ratingsDto = new HashSet<UserRatingDtoInfo>();
			if(ratings != null && ratings.size() > 0){
				for(UserRating rating : ratings){
					ratingsDto.add((UserRatingDtoInfo) getConverter().convertEntityToDto(rating));
				}
			}
			return ratingsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}

	@Override
	@Cacheable(cacheName="rating")
	@Transactional
	public Set<UserRatingDtoInfo> getUserRatingByContent(Integer contentId) throws CommunityException, TechnicalException {
		List<UserRating> productrating = null;
		List<UserRating> vigneronrating = null;
		try {
			productrating = userRatingDao.findByProductContentId(contentId);
			vigneronrating = userRatingDao.findByVigneronContentId(contentId);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		} try {
			List<UserRating> ratings = new ArrayList<UserRating>();
			if(productrating != null){
				ratings.addAll(productrating);
			}
			if(vigneronrating != null){
				ratings.addAll(vigneronrating);
			}
			Set<UserRatingDtoInfo> ratingsDto = new HashSet<UserRatingDtoInfo>();
			if(ratings != null && ratings.size() > 0){
				for(UserRating rating : ratings){
					ratingsDto.add((UserRatingDtoInfo) getConverter().convertEntityToDto(rating));
				}
			}
			return ratingsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}

	@Override
	@Cacheable(cacheName="rating")
	@Transactional
	public Set<UserRatingDtoInfo> getUserRatingByKey(String key) throws CommunityException, TechnicalException {
		List<UserRating> productrating = null;
		List<UserRating> vigneronrating = null;
		try {
			productrating = userRatingDao.findByProductContentKey(key);
			vigneronrating = userRatingDao.findByVigneronContentKey(key);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		} try {	
			List<UserRating> ratings = new ArrayList<UserRating>();
			if(productrating != null){
				ratings.addAll(productrating);
			}
			if(vigneronrating != null){
				ratings.addAll(vigneronrating);
			}
			Set<UserRatingDtoInfo> ratingsDto = new HashSet<UserRatingDtoInfo>();
			if(ratings != null && ratings.size() > 0){
				for(UserRating rating : ratings){
					ratingsDto.add((UserRatingDtoInfo) getConverter().convertEntityToDto(rating));
				}
			}
			return ratingsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}

	@Override
	@Cacheable(cacheName="rating")
	@Transactional
	public Set<UserRatingDtoInfo> getUserRatingByUser(Integer userId) throws CommunityException, TechnicalException {
		List<UserRating> ratings = null;
		try {
			ratings = userRatingDao.findByUserId(userId);
		} catch (Throwable e) {
			throw new TechnicalException(TechnicalException.DATABASE,e);
		} try {
			Set<UserRatingDtoInfo> ratingsDto = new HashSet<UserRatingDtoInfo>();
			if(ratings != null && ratings.size() > 0){
				for(UserRating rating : ratings){
					ratingsDto.add((UserRatingDtoInfo) getConverter().convertEntityToDto(rating));
				}
			}
			return ratingsDto;
		} catch (DtoException e) {
			throw new TechnicalException(TechnicalException.CONVERT,e);
		}
	}

	public DtoFactory getDtoFactory() {
		return dtoFactory;
	}

	public void setDtoFactory(DtoFactory dtoFactory) {
		this.dtoFactory = dtoFactory;
	}

	public EntityDtoConverter getConverter() {
		return converter;
	}

	public void setConverter(EntityDtoConverter converter) {
		this.converter = converter;
	}

	public UserLogRepository getUserLogDao() {
		return userLogDao;
	}

	public void setUserLogDao(UserLogRepository userLogDao) {
		this.userLogDao = userLogDao;
	}

	public UserRatingRepository getUserRatingDao() {
		return userRatingDao;
	}

	public void setUserRatingDao(UserRatingRepository userRatingDao) {
		this.userRatingDao = userRatingDao;
	}

	public UserCommentRepository getUserCommentDao() {
		return userCommentDao;
	}

	public void setUserCommentDao(UserCommentRepository userCommentDao) {
		this.userCommentDao = userCommentDao;
	}

	
}
